#include <Arduino.h>
#include "hub75e.h"
#include "analog_clock.h"
#include "clock_manager.h"
#include "espWifiCfg.h"
#include "ntpTime.h"
#include "display_config.h"
#include "fonts.h"

// 引脚定义 (使用宏定义，便于维护和理解)
const uint8_t pins[14] = {PIN_CLK, PIN_LE, PIN_OE, PIN_A, PIN_B, PIN_C, PIN_D, PIN_E, PIN_R1, PIN_G1, PIN_B1, PIN_R2, PIN_G2, PIN_B2};

Panel panel(DISPLAY_WIDTH, DISPLAY_HEIGHT, NUM_SCAN, pins);
EspWifiCfg wifiCfg;
NTPTime ntpTime;

// 状态变量
bool wifiConnected = false;
unsigned long lastTimeUpdate = 0;
unsigned long lastClockUpdate = 0;
unsigned long lastNTPAttempt = 0;
const unsigned long NTP_UPDATE_INTERVAL = 3600000;
const unsigned long CLOCK_UPDATE_INTERVAL = 1000;

// Helper function to draw text using 5x8 font with left alignment
void drawText5x8(uint16_t x, uint16_t y, const char* text, uint8_t r, uint8_t g, uint8_t b) {
    uint16_t currentX = x;
    for (size_t i = 0; text[i] != '\0'; ++i) {
        int idx = fontIndex(text[i]);
        for (uint8_t row = 0; row < 8; ++row) {
            uint8_t bits = font5x8[idx][row];
            for (uint8_t col = 0; col < 5; ++col) {
                if (bits & (1 << (4 - col))) {
                    panel.drawPixel(currentX + col, y + row, r, g, b);
                }
            }
        }
        currentX += 6; // 5 pixels wide + 1 pixel spacing
    }
}

// 绘制状态信息（使用 panel.width / panel.height，避免 relying on macros at runtime）
void drawStatusInfo() {
    // Optimized status drawing with reduced calculations and improved readability
    constexpr uint16_t indicatorSize = 4; // 4x4 pixel status squares
    constexpr uint16_t gap = 1; // gap between indicators
    constexpr uint16_t wifiY = 0;
    constexpr uint16_t ntpY = indicatorSize + gap;
    
    // Wi-Fi status indicator (top-left)
    uint8_t r, g, b;
    if (wifiCfg.reconfigNeeded()) {
        // Blink red for reconfiguration needed
        bool on = ((millis() / 400) & 1) == 0; // 2.5Hz blink, bit operation faster than modulo
        r = on ? 200 : 0;  // Slightly dimmed for better visibility
        g = b = 0;
    } else if (wifiConnected) {
        r = 0; g = 200; b = 0; // Green when connected
    } else {
        r = 200; g = b = 0; // Red when disconnected
    }
    panel.fillRect(0, wifiY, indicatorSize - 1, wifiY + indicatorSize - 1, r, g, b);
    
    // NTP status indicator (below Wi-Fi)
    if (ntpTime.isTimeValid()) {
        panel.fillRect(0, ntpY, indicatorSize - 1, ntpY + indicatorSize - 1, 0, 0, 200); // Blue
    } else {
        panel.fillRect(0, ntpY, indicatorSize - 1, ntpY + indicatorSize - 1, 200, 200, 0); // Yellow
    }
}

void setup() {
    Serial.begin(115200);
    panel.begin();
    
    // Boot splash screen with startup information using 5x8 font
    panel.clearScreen();
    panel.setBackgound(0, 0, 0); // Black background
    
    // Display project name at top of panel using 5x8 font
    const char* projectName = "CalendarClock V1.0.3";
    drawText5x8(2, 1, projectName, 0, 255, 0); // Green text, top-aligned
    
    Serial.println("=== CalendarClock_V1.0.3 ===");
    
    // Show initialization steps with compact spacing (9 pixels between lines)
    drawText5x8(2, 11, "Initializing...", 0, 255, 0);
    delay(1000);
    
    // Initialize Wi-Fi configuration
    drawText5x8(2, 20, "WiFi Config", 0, 255, 0);
    Serial.println("Starting WiFi configuration...");
    wifiCfg.begin();
    delay(1000);
    
    // Initialize NTP
    drawText5x8(2, 29, "NTP Setup", 0, 255, 0);
    Serial.println("Starting NTP service...");
    ntpTime.begin();
    delay(1000);
    
    // System ready
    drawText5x8(2, 38, "System Ready!", 0, 255, 0);
    Serial.println("System initialization complete");
    delay(2000);
    
    // Keep system/local timezone as configured (default). We'll request the right panel time
    // explicitly for San Francisco when drawing.

    panel.clearScreen();
    // Draw initial clocks immediately (even before Wi‑Fi/NTP) so boot isn't blank
    maybeUpdateClock(panel, ntpTime, lastClockUpdate, 0, -8);
    drawStatusInfo();
    Serial.println("ESP32 LED clock started");
}

void loop() {
    wifiCfg.loop();

    // 检查WiFi状态（封装到 EspWifiCfg）
    bool wifiStatusChanged = wifiCfg.updateWifiStatus(wifiConnected, lastNTPAttempt);

    // NTP时间同步（封装到 NTPTime）
    if (wifiConnected) {
        // If we just connected, trigger a near-immediate sync once
        if (wifiStatusChanged) {
            ntpTime.attemptSyncIfNeeded(lastNTPAttempt, 1000);
        }
        ntpTime.attemptSyncIfNeeded(lastNTPAttempt, NTP_UPDATE_INTERVAL);
    }

    // 更新时钟显示（封装到 clock_manager）
    // Pass -8 to draw the right panel in San Francisco time
        // Update clock display (clock_manager will redraw both panels when needed)
        if (maybeUpdateClock(panel, ntpTime, lastClockUpdate, CLOCK_UPDATE_INTERVAL, -8)) {
            // Clock redrawn once per second
        }

    // Redraw status indicators at optimal frequency for smooth blinking
    static unsigned long lastStatusDraw = 0;
    constexpr unsigned long statusUpdateInterval = 80; // 12.5 FPS - good balance between smoothness and CPU usage
    if (millis() - lastStatusDraw >= statusUpdateInterval) {
        drawStatusInfo();
        lastStatusDraw = millis();
    }

    // Debug output showing left/right times (every 5 seconds)
    static unsigned long lastDebug = 0;
    if (millis() - lastDebug >= 5000) {
        lastDebug = millis();
        
        if (ntpTime.isTimeValid()) {
            // Get left panel time (local time)
            uint8_t leftHour = ntpTime.getHour();
            uint8_t leftMin = ntpTime.getMinute();
            uint8_t leftSec = ntpTime.getSecond();
            
            // Get right panel time (Pacific time with DST)
            uint8_t rightHour, rightMin, rightSec, wday;
            int year, month, day;
            bool hasRightTime = ntpTime.getPacificTime(rightHour, rightMin, rightSec, wday, year, month, day);
            
            if (hasRightTime) {
                Serial.printf("[%lu] Left(Local): %02d:%02d:%02d | Right(Pacific): %02d:%02d:%02d %s | Heap: %u\n",
                             millis(), leftHour, leftMin, leftSec, 
                             rightHour, rightMin, rightSec, ntpTime.getPacificTimeZoneAbbrev(),
                             ESP.getFreeHeap());
            } else {
                Serial.printf("[%lu] Left(Local): %02d:%02d:%02d | Right: N/A | Heap: %u\n",
                             millis(), leftHour, leftMin, leftSec, ESP.getFreeHeap());
            }
        } else {
            // Show system uptime when NTP not available
            unsigned long totalSeconds = millis() / 1000;
            uint8_t sysHour = (totalSeconds / 3600) % 24;
            uint8_t sysMin = (totalSeconds / 60) % 60;
            uint8_t sysSec = totalSeconds % 60;
            Serial.printf("[%lu] System uptime: %02d:%02d:%02d | NTP: Not synced | Heap: %u\n",
                         millis(), sysHour, sysMin, sysSec, ESP.getFreeHeap());
        }
    }

    delay(5); // Reduced from 10ms - better responsiveness
}